#include <stdio.h>

//#include <mach/mach_port.h>
//#include <mach/mach_interface.h>
//#include <mach/mach_init.h>

#include <IOKit/pwr_mgt/IOPMLib.h>
#include <IOKit/IOMessage.h>

io_connect_t  root_port; // a reference to the Root Power Domain IOService

void MySleepCallBack( void * refCon, io_service_t service, natural_t messageType, void * messageArgument )
{
    printf( "messageType %08lx, arg %08lx\n",
        (long unsigned int)messageType,
        (long unsigned int)messageArgument );

    switch ( messageType )
    {
        case kIOMessageCanSystemSleep:
            /* Idle sleep is about to kick in. This message will not be sent for forced sleep.
                Applications have a chance to prevent sleep by calling IOCancelPowerChange.
                Most applications should not prevent idle sleep.

                Power Management waits up to 30 seconds for you to either allow or deny idle sleep.
                If you don't acknowledge this power change by calling either IOAllowPowerChange
                or IOCancelPowerChange, the system will wait 30 seconds then go to sleep.
            */

            //Uncomment to cancel idle sleep
            //IOCancelPowerChange( root_port, (long)messageArgument );
            // we will allow idle sleep
            printf("System will idle sleep\n");
            IOAllowPowerChange( root_port, (long)messageArgument );
            break;

        case kIOMessageSystemWillSleep:
            /* The system WILL go to sleep. If you do not call IOAllowPowerChange or
                IOCancelPowerChange to acknowledge this message, sleep will be
                delayed by 30 seconds.

                NOTE: If you call IOCancelPowerChange to deny sleep it returns kIOReturnSuccess,
                however the system WILL still go to sleep.
            */
            printf("System will sleep\n");
            IOAllowPowerChange( root_port, (long)messageArgument );
            break;

        case kIOMessageSystemWillPowerOn:
            //System has started the wake up process...
            printf("System has started the wake up process\n");
            break;

        case kIOMessageSystemHasPoweredOn:
            //System has finished waking up...
            printf("System has finished waking up...\n");
            break;

        case kIOMessageSystemWillPowerOff:
            printf("System will power off\n");
            break;

        case kIOMessageSystemWillRestart:
            printf("System will restart\n");
            break;

        default:
            break;
    }
}


int main( int argc, char **argv )
{
    IONotificationPortRef  notifyPortRef; // notification port allocated by IORegisterForSystemPower
    io_object_t            notifierObject; // notifier object, used to deregister later
    void*                  refCon; // this parameter is passed to the callback

    // register to receive system sleep notifications

    root_port = IORegisterForSystemPower( NULL, &notifyPortRef, MySleepCallBack, &notifierObject );
    if ( root_port == 0 )
    {
        printf("IORegisterForSystemPower failed\n");
        return 1;
    }

    // add the notification port to the application runloop
    CFRunLoopAddSource( CFRunLoopGetCurrent(),
            IONotificationPortGetRunLoopSource(notifyPortRef), kCFRunLoopCommonModes );

    /* Start the run loop to receive sleep notifications. Don't call CFRunLoopRun if this code
        is running on the main thread of a Cocoa or Carbon application. Cocoa and Carbon manage
        the main thread's run loop for you as part of their event handling mechanisms. */
    CFRunLoopRun();

    //Not reached, CFRunLoopRun doesn't return in this case.
    return (0);
}